package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author mgx
 * @version 1.0
 * @description: TODO
 * @date 2022-12-03 1:13
 */
@Service
@SuppressWarnings("all")
public class CartServiceImpl implements CartService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProductFeignClient productFeignClient;

    /**
     * 加入购物车
     * @param userId
     * @param skuId
     * @param skuNum
     *
     *
     * 存储数据（redis数据结构）：
     * 1. 区分用户 2. 区分商品 -- hash结构
     *
     * key：用户id
     * field: 商品skuId
     * value: 商品对象信息cartInfo
     */
    @Override
    public void addToCart(String userId, Long skuId, Integer skuNum) {
        // 获取购物key
        String cartKey = this.getKey(userId);
        // 保存购物车信息到redis中
        // 获取值 hash数据结构存储
        // String -> user:userId:cart String -> skuId CartInfo -> 购物车信息
        BoundHashOperations<String, String, CartInfo> boundHashOps = redisTemplate.boundHashOps(cartKey);
        CartInfo cartInfo = null;
        // 1. 判断该用户购物车是否已经有了该商品
        if(boundHashOps.hasKey(skuId.toString())) {
            // 1.1 包含，加数量
            // 取出值
            cartInfo = boundHashOps.get(skuId.toString());
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            cartInfo.setIsChecked(1);
            // 设置当前的实时价格 -- 有可能当前的价格有促销之类的
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(skuId));
            cartInfo.setUpdateTime(new Date());
        }else {
            // 1.2 不包含， 数量为新添加的值
            // 创建一个对象，往里面封装该商品信息
            cartInfo = new CartInfo();
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            // 远程调用service-product模块获取skuInfo
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setSkuNum(skuNum);
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            // 设置实时价格
            cartInfo.setSkuPrice(skuInfo.getPrice());
            cartInfo.setCreateTime(new Date());
            cartInfo.setUpdateTime(new Date());
        }
        // 添加信息到购物车中
        boundHashOps.put(skuId.toString(), cartInfo);
    }

    /**
     * 展示购物车
     *
     * 第二版:
     *  合并购物车
     *  1. 区别用户
     *  2. 区别商品
     *  业务思路：
     *  1. 判断当前登录状态 -- 未登录的话直接返回未登录状态下的购物车
     *  2. 查询redis未登录状态下，是否存在购物车信息 -- 结算
     *      2.1 有 -- 合并
     *          2.1.1 循环遍历我们的未登录的购物车信息列表
     *          2.1.2 判断登录的购物车信息列表中是否存在未登录的购物车信息列表的skuId
     *              2.1.2.1 存在，更新数量，时间，选中状态
     *              2.1.2.2 不存在，把当前未登录购物车列表信息中的这一个cartInfo加入登录的购物车信息列表中 -- 更新userId和时间
     *          2.1.3 存储
     *          2.1.4 清除未登录的购物车信息列表
     *      2.2 没有 -- 直接查询登录状态下的userId的购物车信息返回即可
     * @param userId
     * @param userTempId
     * @return
     */
    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {
        // 获取临时用户id的购物车信息
        List<CartInfo> noLoginCartList = null;
        if(!StringUtils.isEmpty(userTempId)) {
            noLoginCartList = redisTemplate.boundHashOps(this.getKey(userTempId)).values();
        }
        // 表示状态未登录 -- userid为空并且noLoginCartList不为空
        if(StringUtils.isEmpty(userId) && !CollectionUtils.isEmpty(noLoginCartList)) {
            // 排序
            noLoginCartList.sort((o1, o2) -> {
                return DateUtil.truncatedCompareTo(o2.getUpdateTime(), o1.getUpdateTime(), Calendar.SECOND);
            });

            return noLoginCartList;
        }
        // 登录后的合并
        List<CartInfo> loginCartList=null;

        //获取登录后的数据
        BoundHashOperations<String,String,CartInfo> boundHashOps = redisTemplate.boundHashOps(this.getKey(userId));
        // 判断未登录状态下是否有购物车信息
        if(!CollectionUtils.isEmpty(noLoginCartList)) {
            // 有, 合并
            // 合并的逻辑：遍历未登录的购物车，判断当前未登录的购物车中的skuId是否存在于登录后的用户的购物车中
            noLoginCartList.forEach(cartInfo -> {
                if(boundHashOps.hasKey(cartInfo.getSkuId().toString())) {
                    // 存在，修改数量
                    // 获取登录状态的购物车对应的skuid的信息
                    CartInfo loginCartInfo = boundHashOps.get(cartInfo.getSkuId().toString());
                    // 更新数量
                    loginCartInfo.setSkuNum(loginCartInfo.getSkuNum()+cartInfo.getSkuNum());
                    // 更新时间
                    loginCartInfo.setUpdateTime(new Date());
                    // 更新选中状态
                    if(cartInfo.getIsChecked().intValue() == 1) {
                        loginCartInfo.setIsChecked(1);
                    }
                    // 存储值
                    boundHashOps.put(cartInfo.getSkuId().toString(), loginCartInfo);
                }else {
                    // 不存在， 创建一个添加到登录状态的购物车
                    // 更新用户id
                    cartInfo.setUserId(userId);
                    // 更新时间
                    cartInfo.setUpdateTime(new Date());
                    // 存储值
                    boundHashOps.put(cartInfo.getSkuId().toString(), cartInfo);
                }
            });

            // 合并之后，删除未登录的购物车
            redisTemplate.delete(this.getKey(userTempId));
        }

        // 获取登录过后的购物车列表
        loginCartList = boundHashOps.values();

        if(CollectionUtils.isEmpty(loginCartList)) {
            return new ArrayList<>();
        }

        // 排序
        loginCartList.sort((o1, o2) -> {
            return DateUtil.truncatedCompareTo(o2.getUpdateTime(), o1.getUpdateTime(), Calendar.SECOND);
        });

        return loginCartList;


        // 创建返回对象
        // List<CartInfo> cartInfoList = null;
        // // 处理临时用户id
        // if(!StringUtils.isEmpty(userTempId)) {
        //     // 获取key
        //     String cartKey = this.getKey(userTempId);
        //     // 从redis中获取值
        //     cartInfoList = redisTemplate.boundHashOps(cartKey).values();
        // }
        // // 处理登录id
        // if(!StringUtils.isEmpty(userId)) {
        //     // 获取key
        //     String cartKey = this.getKey(userId);
        //     // 从redis中获取值
        //     cartInfoList = redisTemplate.boundHashOps(cartKey).values();
        // }
        // // 排序功能
        // if(!CollectionUtils.isEmpty(cartInfoList)) {
        //     cartInfoList.sort((o1, o2) -> {
        //         return DateUtil.truncatedCompareTo(o2.getUpdateTime(), o1.getUpdateTime(), Calendar.SECOND);
        //     });
        // }
        // return cartInfoList;
        // return null;
    }

    /**
     * 购物车选中状态的变更
     * @param userId
     * @param skuId
     * @param isChecked
     */
    @Override
    public void checkCart(String userId, Long skuId, Integer isChecked) {
        // 根据userId获取key
        String cartKey = this.getKey(userId);
        // 获取值
        BoundHashOperations<String, String, CartInfo> boundHashOps = redisTemplate.boundHashOps(cartKey);
        CartInfo cartInfo = boundHashOps.get(skuId.toString());
        if(cartInfo != null) {
            cartInfo.setIsChecked(isChecked);
            // 存储回去
            boundHashOps.put(skuId.toString(), cartInfo);
        }
    }

    /**
     * 删除购物车
     * @param userId
     * @param skuId
     */
    @Override
    public void deleteCart(String userId, Long skuId) {
        // redis中直接删除不存在的key不会报错，所以直接删除即可
        BoundHashOperations<String, String, CartInfo> boundHashOps = redisTemplate.boundHashOps(this.getKey(userId));
        if(boundHashOps.hasKey(skuId.toString())) {
            // 有值删除
            boundHashOps.delete(skuId.toString());
        }
    }

    /**
     * 查询用户选中状态的购物车信息
     * @param userId
     * @return
     */
    @Override
    public List<CartInfo> getCartCheckedList(Long userId) {
        // 从redis中获取选中状态的购物车信息
        // 根据cartKey获取购物车信息
        BoundHashOperations<String, String, CartInfo> boundHashOps = redisTemplate.boundHashOps(this.getKey(userId.toString()));
        // 获取值列表
        List<CartInfo> cartInfoList = boundHashOps.values();
        List<CartInfo> isCheckedList = cartInfoList.stream().filter(cartInfo -> {
            // 获取的时候重新更新一次价格 -- 方便后面下订单时复用 -- 校验价格
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
            // 进行过滤
            // 只要选中状态的
            return cartInfo.getIsChecked().intValue() == 1;
        }).collect(Collectors.toList());
        return isCheckedList;
    }

    /**
     * 获取key
     * user:userId:cart skuId cartInfo
     * @param userId
     * @return
     */
    private String getKey(String userId) {
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }
}
